package com.galaxy.controller;

import com.alibaba.fastjson.JSON;
import com.galaxy.service.FileUpdateService;
import com.galaxy.util.M;
import com.galaxy.util.PUtil;
import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.GetObjectTagsArgs;
import io.minio.MinioClient;
import io.minio.errors.*;
import io.minio.messages.Tags;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;

import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author anjie
 * @version 1.0
 * @date 2020/8/21 9:21
 * @email anjie@032t.com
 */
@RestController
@RequestMapping("/galaxy")
public class PictureGetController {

    @Autowired
    FileUpdateService fileUpdateService;

    @Autowired
    MinioClient minioClient;

//    @Value("${minio.bucketName}")
    private String bucketName;

    /**
     * 图片获取控制器
     *
     * @param wh   图片宽度 图片高度
     * @return json
     */
    @RequestMapping({
//            "/picture/{bn}/{path}/{n}",
//            "/picture/{bn}/{path}/{wh}/{n}",
            "/picture/{bn}/{wh}/**"
    })
    public void getPicture(
                            HttpServletRequest request,
                             HttpServletResponse response,
                             @PathVariable("bn") String bucketName,
//                             @PathVariable("path") String path,
//                             @PathVariable("n") String name,
                             @PathVariable(required = false, value = "wh") String wh
                           ) throws Exception {

        this.bucketName = bucketName;
        boolean b = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if(!b){
            response.getWriter().println("error No BucketName found");
            return;
        }

        String url_origin = "origin";
        String split_regex = "/";
        //检查路径是预期的
        if(wh!= null && !wh.equals(url_origin)){
            boolean isMatch = Pattern.matches("([0-9]{1,})-([0-9]{1,})",wh);
            if(!isMatch){
                response.addHeader(HttpHeaders.CONTENT_TYPE,"application/json");
                M err = M.err();
                err.setMsg("The path does not meet the requirements. It should be origin or xxx-xxx (XXX is an integer) !");
                String s = JSON.toJSONString(err);
                response.getWriter().println(s);
                return;
            }
        }
        //判断是不是 url_origin 如果是就把 wh设置为 null 代表没有 指定图片的大小
        if(wh!= null && wh.equals(url_origin)) wh = null;

        String path,name;
        String servletPath = request.getServletPath();
        String[] pathlist = servletPath.substring(1).split(split_regex);
        //检查路径是否正确
        if(pathlist.length<6){
            response.addHeader(HttpHeaders.CONTENT_TYPE,"application/json");
            M err = M.err();
            err.setMsg("The path is not correct. The minimum path is 6 layers !");
            String s = JSON.toJSONString(err);
            response.getWriter().println(s);
            return;
        }

        //解析文件名称
        String front = servletPath.substring(0, servletPath.lastIndexOf(split_regex));
        String filename = servletPath.substring(front.length() + split_regex.length(), servletPath.length());
        name = filename;
        //解析路径
        int i = url_origin.length() + split_regex.length();
        if(wh != null){
            i = wh.length() + split_regex.length() ;
        }

        String subfront = servletPath.substring(0, servletPath.lastIndexOf(bucketName) + i );
        String subpath = servletPath.substring(subfront.length() + bucketName.length() + split_regex.length(), servletPath.length());
        path = subpath.substring(0, subpath.length() - (filename.length() + split_regex.length()));


        Integer w=null,h=null;
        if(wh!=null) {
            String[] split = wh.split("-");
            if(split.length == 2) {
                w = Integer.valueOf(split[0]);
                h = Integer.valueOf(split[1]);
            }

            String ispath = path+ "/" + wh + "/" + name;

            try{
                minioClient.getObjectTags(
                        GetObjectTagsArgs.builder()
                                .bucket(bucketName)
                                .object(ispath)
                                .build()
                );
                //图片获取逻辑
                getPic(response,wh, path+ "/" + wh, name, null, null,false);
            }catch (ErrorResponseException e){
                //图片获取逻辑
                getPic(response,wh, path, name, w, h,true);
            }

        }else{
            getPic(response,wh, path, name, w, h,false);
        }

    }

    /**
     * 图片输出操作
     * @param response http输出楼
     * @param path 文件路径
     * @param name 文件名称
     * @param w 图片高度
     * @param h 图片宽度
     * @throws Exception
     */
    private void getPic(HttpServletResponse response,String wh, String path, String name, Integer w, Integer h,Boolean c) throws Exception {

        String opath = "";
        if (path != null) {

            opath = path;
            path += "/" + name;

            InputStream object;
            BufferedInputStream buffin;
            Map<String, String> obj;
            try {
                object = minioClient.getObject(
                        GetObjectArgs.builder()
                                .bucket(bucketName)
                                .object(path)
                                .build()
                );

                //获取文件对应的 tags
                Tags objectTags = minioClient.getObjectTags(
                        GetObjectTagsArgs.builder()
                                .bucket(bucketName)
                                .object(path)
                                .build()
                );
                obj = objectTags.get();

                buffin = new BufferedInputStream(object);
                int i = name.lastIndexOf(".");
                String suffix;
                if(i != -1)
                    suffix = name.substring(i);
                else
                    suffix = "";
                if(w !=null && h !=null){
                    buffin = new BufferedInputStream(new PUtil().fixPicture(buffin, w, h, suffix));
                    //是否进行缓存操作
                    if(c){
                        MultipartFile multipartFile = new MockMultipartFile(name,name,obj.get("contentType"), buffin);
                        String spath = opath+"/"+wh+"/"+name;
                        fileUpdateService.putFile(multipartFile,bucketName,null,spath);
                        //应为 执行 fileUpdateService.putFile 会导致输入流关闭 所以要重新打开输入流
                        object = minioClient.getObject(
                                GetObjectArgs.builder()
                                        .bucket(bucketName)
                                        .object(spath)
                                        .build()
                        );
                        buffin = new BufferedInputStream(object);

                    }
                }
            } catch (ErrorResponseException e) {
                response.addHeader(HttpHeaders.CONTENT_TYPE,"application/json");
                M err = M.err();
                err.setMsg("parameter is incorrect !");
                String s = JSON.toJSONString(err);
                response.getWriter().println(s);
                return;
            } catch (IllegalArgumentException e) {
                response.addHeader(HttpHeaders.CONTENT_TYPE,"application/json");
                M err = M.err();
                err.setMsg("Object name cannot be empty !");
                String s = JSON.toJSONString(err);
                response.getWriter().println(s);
                return;
            }

            //设置响应头
            response.addHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
            response.addHeader(HttpHeaders.CONTENT_TYPE,obj.get("contentType"));

            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
            byte[] cache = new byte[4096];
            int nRead = 0;
            while ((nRead = buffin.read(cache)) != -1) {
                bufferedOutputStream.write(cache, 0, nRead);
            }
            bufferedOutputStream.flush();
        } else {
            response.addHeader(HttpHeaders.CONTENT_TYPE,"application/json");
            M err = M.err();
            String s = JSON.toJSONString(err);
            response.getWriter().println(s);
        }
    }

}
